from gluon.storage import Storage

def treeVisual():
    tree = buildTree( { 'nodes': db( db.node.treeId == request.vars.treeId ).select( db.node.id, db.node.label, db.node.left, db.node.right, orderby = db.node.left ) } )
    
    return widgetWrapper( { 'data':
                            { 'treeInfo': { 'id': request.vars.treeId,
                                            'tree': convertTreeToDict( tree ),
                                            'events' : { 'handleLabelClick': 'standardEditLabel' },
                                            'labelRender': 'sync',
                                            'labelType': 'html' } } } )


def inlineTreeVisual():

    tree = buildTree( { 'nodes': db( db.node.treeId == request.vars.treeId ).select( db.node.id, db.node.label, db.node.left, db.node.right, orderby = db.node.left ) } )
    
    treeInfo = getTreeInfo( { 'node': tree } )

    buffer = 100
    generationSeparation = 20
    siblingSeparation = 20
                                       
    canvasWidth =  generationSeparation * treeInfo['depth'] + ( buffer * 2 )
    canvasHeight = siblingSeparation * treeInfo['tips'] + ( buffer * 2 )

    firstTip = { 'x': canvasWidth - buffer,
                 'y': buffer }

    labels = []

    pathString = generatePathString( { 'node': tree,
                                       'currentTip': firstTip,
                                       'depth': treeInfo['depth'],
                                       'pathString': '',
                                       'labels': labels,
                                       'config': { 'generationSeparation': generationSeparation,
                                                   'siblingSeparation': siblingSeparation } } )


    return widgetWrapper( { 'data' : { 'pathString': pathString,
                                       'labels': labels,
                                       'canvasWidth': ( generationSeparation * treeInfo['depth'] ) + ( buffer * 2 ),
                                       'canvasHeight': ( siblingSeparation * treeInfo['tips'] ) + ( buffer * 2 ) } } )


def getTreeInfo( p ):
    
    tips = 0
    depth = 1

    returnedInfo = []

    if p['node'].children:
        mostDepth = 0
        for child in p['node'].children:
            returnedInfo = getTreeInfo( { 'node': child } )
            tips = tips + returnedInfo['tips']
            if returnedInfo['depth'] > mostDepth:
                mostDepth = returnedInfo['depth']

        depth = depth + mostDepth
    
    else:
        tips = tips + 1    



    return { 'tips': tips, 'depth': depth }   


def generatePathString( p ):

    children = p['node'].children

    for child in children:
        p['pathString'] = generatePathString( { 'node': child,
                                                'currentTip': p['currentTip'],
                                                'depth': p['depth'] - 1,
                                                'pathString': p['pathString'],
                                                'labels': p['labels'],
                                                'config': p['config'] } )

    if children:
        p['node'].x = children[0].x + children[0].dx
        p['node'].dx = - p['config']['generationSeparation']
        p['node'].y = ( children[ -1 ].y + children[0].y ) / 2

        p['pathString'] = ''.join( [ p['pathString'], "M", str(p['node'].x), ",", str(children[0].y), "L", str(p['node'].x), ",", str(children[ -1 ].y) ] )

    else:

        p['node'].x = p['currentTip']['x']
        p['node'].dx = -( p['config']['generationSeparation'] * p['depth'] )
        p['node'].y = p['currentTip']['y']

        p['currentTip']['y'] += p['config']['siblingSeparation']

    p['pathString'] = ''.join( [ p['pathString'], "M", str(p['node'].x), ",", str(p['node'].y), "l", str(p['node'].dx), ",0" ] )

    if( p['node'].label ):
        p['labels'].append( { 'text': p['node'].label, 'x': p['node'].x, 'y': p['node'].y } )

    return p['pathString']



def modalBox():
    return widgetWrapper( { 'data': { },
                            'view': True } )    


def widgetWrapper( p ):
    import gluon.contrib.simplejson as json

    if 'view' not in p:
         response.view = 'widget/wrapper.load'
  
    p['data']['containerId'] = request.cid; 

    response.write( SCRIPT( ''.join( [ 'widgetResponseHandler("', request.function, '", ', 'eval( "(" + \'', json.dumps( p['data'] ), '\' + ")" ) );' ] ), _language='javascript' ), escape=False )

    if 'view' not in p:
        return dict( )
    else:
        return p['data']


def convertTreeToDict( tree ):

    treeDict = { 'id': tree.id, 'label': tree.label, 'children': [ ] }

    
    def traverseTree( p ):

        currentDict = { }
        currentDict['id'] = p['node'].id
        currentDict['label'] = p['node'].label
        currentDict['children'] = [ ]

        for child in p['node'].children:
            currentDict['children'].append( traverseTree( { 'node': child } ) )

        return currentDict


    for child in tree.children:
        treeDict['children'].append( traverseTree( { 'node': child } ) )

    return treeDict







def buildTree( p ):
    phylo = local_import('phylo', reload=True)
    
    root = None
    currentNode = None

    for node in p['nodes']:
        if currentNode:
            while( currentNode.rightId < node.right ):
                currentNode = currentNode.parent

        treeNode = phylo.Node()
        treeNode.id = node.id
        treeNode.rightId = node.right;
        treeNode.label = node.label;

        if currentNode:
            currentNode.add_child( treeNode )
            currentNode = treeNode
        else:
            root = treeNode
            currentNode = treeNode

    return root

